#ifndef _LJ_LOG_
#define _LJ_LOG_

#include <aos/kernel.h>

#define lj_csp_printf(fmt, ...)  printf(fmt,##__VA_ARGS__) // csp_printf(fmt, ##__VA_ARGS__); 

extern unsigned int lj_log_level;
extern unsigned int lj_log_head;

extern int lj_csp_printf(const char *fmt, ...);

static inline unsigned int lj_log_get_level(void)
{
    return lj_log_level;
}

static inline unsigned int lj_log_get_head(void)
{
    return lj_log_head;
}



typedef enum {
    LJ_LL_NONE,  /* disable log */
    LJ_LL_FATAL, /* fatal log will output */
    LJ_LL_ERROR, /* fatal + error log will output */
    LJ_LL_WARN,  /* fatal + warn + error log will output(default level) */
    LJ_LL_INFO,  /* info + warn + error log will output */
    LJ_LL_DEBUG, /* debug + info + warn + error + fatal log will output */
    LJ_LL_SET1,
    LJ_LL_SET2,
    LJ_LL_SET3
} lj_log_level_t;

enum log_level_bit {
    LJ_LL_V_NONE_BIT = -1,
    LJ_LL_V_FATAL_BIT,
    LJ_LL_V_ERROR_BIT,
    LJ_LL_V_WARN_BIT,
    LJ_LL_V_INFO_BIT,
    LJ_LL_V_DEBUG_BIT,
    LJ_LL_V_SET1_BIT,
    LJ_LL_V_SET2_BIT,
    LJ_LL_V_SET3_BIT,
    LJ_LL_V_MAX_BIT
};

#define LJ_LOG_LEVEL lj_log_get_level()
#define LJ_LOG_HEAD lj_log_get_head()

#define LJ_LL_V_NONE  0
#define LJ_LL_V_ALL   0XFF
#define LJ_LL_V_FATAL (1 << LJ_LL_V_FATAL_BIT)
#define LJ_LL_V_ERROR (1 << LJ_LL_V_ERROR_BIT)
#define LJ_LL_V_WARN  (1 << LJ_LL_V_WARN_BIT)
#define LJ_LL_V_INFO  (1 << LJ_LL_V_INFO_BIT)
#define LJ_LL_V_DEBUG (1 << LJ_LL_V_DEBUG_BIT)
#define LJ_LL_V_SET1 (1 << LJ_LL_V_SET1_BIT)
#define LJ_LL_V_SET2 (1 << LJ_LL_V_SET2_BIT)
#define LJ_LL_V_SET3 (1 << LJ_LL_V_SET3_BIT)


/*
 * color def.
 * see http://stackoverflow.com/questions/3585846/color-text-in-terminal-applications-in-unix
 */
#define COL_DEF "\x1B[0m"  /* white */
#define COL_RED "\x1B[31m" /* red */
#define COL_GRE "\x1B[32m" /* green */
#define COL_BLU "\x1B[34m" /* blue */
#define COL_YEL "\x1B[33m" /* yellow */
#define COL_WHE "\x1B[37m" /* white */
#define COL_CYN "\x1B[36m"
#define COL_MAG "\x1B[35m"

            // csp_printf("[%06d]<" LVL "> ", (unsigned)lj_now_ms()); \
            // csp_printf(FMT, ##__VA_ARGS__); \
            // csp_printf("\r\n"); 
extern unsigned int lj_now_ms(void);

#define lj_log_print(CON, MOD, COLOR, LVL, FMT, ...) \
    do { \
        if (LJ_LOG_LEVEL & CON) { \
            if(LJ_LOG_HEAD){\
            lj_csp_printf("[%06d]<" LVL "-" MOD"> ", (unsigned)lj_now_ms()); \
            }\
            lj_csp_printf(FMT, ##__VA_ARGS__); \
            if(LJ_LOG_HEAD){\
            lj_csp_printf("\r\n"); \
            }\
        } \
    } while (0)


#define LJ_LOGF_IMPL(mod, fmt, ...) \
        lj_log_print(LJ_LL_V_FATAL, mod, COL_RED, "F", fmt, ##__VA_ARGS__)
#define LJ_LOGE_IMPL(mod, fmt, ...) \
        lj_log_print(LJ_LL_V_ERROR, mod, COL_YEL, "E", fmt, ##__VA_ARGS__)
#define LJ_LOGW_IMPL(mod, fmt, ...) \
        lj_log_print(LJ_LL_V_WARN, mod, COL_BLU, "W", fmt, ##__VA_ARGS__)
#define LJ_LOGI_IMPL(mod, fmt, ...) \
        lj_log_print(LJ_LL_V_INFO, mod, COL_GRE, "I", fmt, ##__VA_ARGS__)
#define LJ_LOGD_IMPL(mod, fmt, ...) \
        lj_log_print(LJ_LL_V_DEBUG, mod, COL_WHE, "D", fmt, ##__VA_ARGS__)
#define LJ_LOG1_IMPL(mod, fmt, ...) \
        lj_log_print(LJ_LL_V_SET1, mod, COL_WHE, "SET1", fmt, ##__VA_ARGS__)
#define LJ_LOG2_IMPL(mod, fmt, ...) \
        lj_log_print(LJ_LL_V_SET2, mod, COL_WHE, "SET2", fmt, ##__VA_ARGS__)
#define LJ_LOG3_IMPL(mod, fmt, ...) \
        lj_log_print(LJ_LL_V_SET3, mod, COL_WHE, "SET3", fmt, ##__VA_ARGS__)

#define LJ_LOG_IMPL(fmt, ...) \
        lj_log_print(AOS_LL_V_ALL, "LJ", COL_DEF, "V", fmt, ##__VA_ARGS__)


/**
 * Set the log level.
 *
 * @param[in]  log_level  level to be set,must be one of LJ_LL_NONE,LJ_LL_FATAL,LJ_LL_ERROR,LJ_LL_WARN,LJ_LL_INFO or LJ_LL_DEBUG.
 */
void lj_set_log_level(lj_log_level_t log_level);

void lj_set_log_head(unsigned char onoff);

/*
 * Log at fatal level.
 *
 * @param[in]  mod  string description of module.
 * @param[in]  fmt  same as printf() usage.
 */
#define LJ_LOGF(mod, fmt, ...) LOGF_IMPL(mod, fmt, ##__VA_ARGS__)

/*
 * Log at error level.
 *
 * @param[in]  mod  string description of module.
 * @param[in]  fmt  same as printf() usage.
 */
#define LJ_LOGE(mod, fmt, ...) LJ_LOGE_IMPL(mod, fmt, ##__VA_ARGS__)

/*
 * Log at warning level.
 *
 * @param[in]  mod  string description of module.
 * @param[in]  fmt  same as printf() usage.
 */
#define LJ_LOGW(mod, fmt, ...) LJ_LOGW_IMPL(mod, fmt, ##__VA_ARGS__)

/*
 * Log at info level.
 *
 * @param[in]  mod  string description of module.
 * @param[in]  fmt  same as printf() usage.
 */
#define LJ_LOGI(mod, fmt, ...) LJ_LOGI_IMPL(mod, fmt, ##__VA_ARGS__)

/*
 * Log at debug level.
 *
 * @param[in]  mod  string description of module.
 * @param[in]  fmt  same as printf() usage.
 */
#define LJ_LOGD(mod, fmt, ...) LJ_LOGD_IMPL(mod, fmt, ##__VA_ARGS__)

/*
 * Log at the level set by lj_set_log_level().
 *
 * @param[in]  fmt  same as printf() usage.
 */
#define LJ_LOG(fmt, ...) LJ_LOG_IMPL(fmt, ##__VA_ARGS__)

#define LJ_LOG1(mod, fmt, ...) LJ_LOG1_IMPL(mod, fmt, ##__VA_ARGS__)
#define LJ_LOG2(mod, fmt, ...) LJ_LOG2_IMPL(mod, fmt, ##__VA_ARGS__)
#define LJ_LOG3(mod, fmt, ...) LJ_LOG3_IMPL(mod, fmt, ##__VA_ARGS__)


#endif